/**
 *  Copyright 2010 Kyle O'Connor, Justin Arling, Mike Mercieca
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package edu.drexel.sd0910.ece01.aqmon.gui.map;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.geom.Point2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.GroupLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.LayoutStyle;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;

import org.apache.log4j.Logger;
import org.jdic.web.BrComponent;
import org.jdic.web.BrMap;
import org.jdic.web.BrMapBalloonSprite;
import org.jdic.web.BrMapMousePos;

import edu.drexel.sd0910.ece01.aqmon.gui.wizard.impl.MapPanel;

/**
 * MapBean built using JDICplus. JDICplus is a Java Win32-extension development
 * kit, enabling developers to use extended Microsoft Windows API functionality.
 * Mainly the project implements the semi-lightweight wrapper component around
 * Microsoft Internet Explorer (IE).
 * 
 * @author Kyle O'Connor
 * 
 */
@SuppressWarnings("serial")
public class MapBean extends JPanel {

	private final static Logger log = Logger.getLogger(MapBean.class);

	private final static String MOUSE_GEO_POSITION = "mouseGeoPos";
	private final static String PROGRESS_BAR = "progressBar";

	private BrMap map; // JDICplus map object
	private JPanel statusPanel;
	private JLabel lbLatName;
	private JLabel lbLonName;
	private JLabel lbLat;
	private JLabel lbLon;
	private JProgressBar progressBar;

	/**
	 * Creates a new JDICplus basic map using GoogleMaps, default zoom level set
	 * to 18 and initializes to hybrid view. Use this constructor to set the
	 * lat/lon starting point of the map.
	 * 
	 * @param initialLat
	 *            latitude map center point
	 * @param initLongitude
	 *            longitude for map center point
	 */
	public MapBean(MapPanel mapPanel, double initialLat, double initLongitude) {
		log.debug("Initializing JDICplus map...");
		map = new CustomBrMap(mapPanel, BrMap.MAP_GOOGLE, initialLat, initLongitude, BrMap.ZOOM_MAX - BrMap.ZOOM_MIN,
				BrMap.VIEW_ROAD | BrMap.VIEW_SATELLITE);
		setup();
	}

	private void setup() {
		BrComponent.DESIGN_MODE = false;
		// hide unwanted stuff on the panel
		map.btGoogleMap.setVisible(false);
		map.btMicrosoftMap.setVisible(false);
		map.btYahooMap.setVisible(false);
		map.btHybridView.setVisible(true);
		map.btRoadView.setVisible(true);
		map.btSatelliteView.setVisible(false);

		// set up status panel
		statusPanel = new JPanel();
		statusPanel.setRequestFocusEnabled(false);
		lbLatName = new JLabel("Latitude:");
		lbLat = new JLabel();
		lbLatName.setHorizontalAlignment(SwingConstants.RIGHT);
		lbLatName.setHorizontalTextPosition(SwingConstants.RIGHT);
		lbLonName = new JLabel("Longitude:");
		lbLon = new JLabel();
		lbLonName.setHorizontalAlignment(SwingConstants.RIGHT);
		lbLonName.setHorizontalTextPosition(SwingConstants.RIGHT);
		progressBar = new JProgressBar();
		progressBar.setVisible(false);

		// status bar layout using swing GroupLayout
		GroupLayout statusPanelLayout = new GroupLayout(statusPanel);
		statusPanel.setLayout(statusPanelLayout);
		statusPanelLayout.setHorizontalGroup(statusPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
				.addGroup(
						statusPanelLayout.createSequentialGroup().addComponent(lbLatName, GroupLayout.PREFERRED_SIZE,
								52, GroupLayout.PREFERRED_SIZE).addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
								.addComponent(lbLat, GroupLayout.PREFERRED_SIZE, 100, GroupLayout.PREFERRED_SIZE)
								.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED).addComponent(lbLonName,
										GroupLayout.PREFERRED_SIZE, 62, GroupLayout.PREFERRED_SIZE).addPreferredGap(
										LayoutStyle.ComponentPlacement.RELATED).addComponent(lbLon,
										GroupLayout.PREFERRED_SIZE, 108, GroupLayout.PREFERRED_SIZE).addPreferredGap(
										LayoutStyle.ComponentPlacement.RELATED).addPreferredGap(
										LayoutStyle.ComponentPlacement.RELATED, 12, Short.MAX_VALUE).addComponent(
										progressBar, GroupLayout.PREFERRED_SIZE, 75, GroupLayout.PREFERRED_SIZE)
								.addContainerGap()));
		statusPanelLayout.setVerticalGroup(statusPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
				.addComponent(lbLatName, GroupLayout.Alignment.CENTER, GroupLayout.DEFAULT_SIZE, 23, Short.MAX_VALUE)
				.addComponent(lbLat, GroupLayout.Alignment.CENTER, GroupLayout.DEFAULT_SIZE, 23, Short.MAX_VALUE)
				.addComponent(lbLonName, GroupLayout.Alignment.CENTER, GroupLayout.DEFAULT_SIZE, 23, Short.MAX_VALUE)
				.addComponent(lbLon, GroupLayout.Alignment.CENTER, GroupLayout.DEFAULT_SIZE, 23, Short.MAX_VALUE)
				.addComponent(progressBar, GroupLayout.Alignment.CENTER, GroupLayout.PREFERRED_SIZE,
						GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE));

		// property change listener for mouse lat/lon and progress bar
		map.addPropertyChangeListener(new PropertyChangeListener() {

			public void propertyChange(PropertyChangeEvent pevt) {
				handlePropertyChanges(pevt);
			}
		});

		// set layout and add components to panel
		this.setLayout(new BorderLayout());
		this.add(map, BorderLayout.CENTER);
		this.add(statusPanel, BorderLayout.SOUTH);
	}

	private void handlePropertyChanges(PropertyChangeEvent evt) {
		String propertyString = evt.getPropertyName();
		if (propertyString.equals(MOUSE_GEO_POSITION)) {
			// you can show the geo coordinates of mouse position here
			final Point2D gp = ((BrMapMousePos) evt.getNewValue()).getMouseGeoPos();
			// update GUI safely on the event dispatch thread
			SwingUtilities.invokeLater(new Runnable() {

				public void run() {
					lbLat.setText(String.format("%3.7f", gp.getX()));
					lbLon.setText(String.format("%3.7f", gp.getY()));
				}
			});

		} else if (propertyString.equals(PROGRESS_BAR)) {
			String stNV = (String) evt.getNewValue();
			if (null == stNV)
				stNV = "";
			String st[] = stNV.split(",");
			int iMax = Integer.parseInt(st[0]), iPos = Integer.parseInt(st[1]);
			if (0 == iMax) {
				progressBar.setVisible(false);
			} else {
				progressBar.setMaximum(iMax);
				progressBar.setValue(iPos);
				progressBar.setVisible(true);
			}
		}
	}

	public void centerOnAddressLocation(String address) {
		if (map.isMapReady()) {
			map.execJS(":_findAddress(\"" + address.replace("\'", "\\\'") + "\")");
		}
	}
	
	public String getCurrentLatitude() {
		return lbLat.getText();
	}
	
	public String getCurrentLongitude() {
		return lbLon.getText();
	}
	
	public void placeLocationBubble(final String nodeID, final String lat, final String lon) {
		final int nodeNumber = Integer.parseInt(nodeID.substring(nodeID.indexOf('N') + 1));
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				BrMapBalloonSprite bl = new BrMapBalloonSprite("<html><b>Node "+nodeNumber+"</b></html>", map.getPoint(lat +","+lon));
				bl.add(map);
				//map.repaint();
			}
		});
	}
	
	public void clearLocationBubble() {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				map.getSprites().clear();
				//map.repaint();
			}
		});
	}

	public class CustomBrMap extends BrMap {
		
		public static final String MOUSE_MOVE_EVENT = "mousemove";
		public static final String MOUSE_UP_EVENT = "mouseup";
		public static final int WHICH_BUTTON = 4;
		public static final String LEFT_BUTTON = "1";
		public static final String RIGHT_BUTTON = "2";
		public static final int MAP_X_POS = 2;
		public static final int MAP_Y_POX = 3;
		public static final int LAT = 2;
		public static final int LON = 3;

		private MapPanel linkedPanel;

		/**
		 * Default constructor for a BrMap.
		 */
		public CustomBrMap() {
			super();
		}

		/**
		 * Special constructor for setting up map properties through a
		 * constructor.
		 * 
		 * @param iMapProvider
		 * @param viewCenterLatitude
		 * @param viewCenterLongitude
		 * @param viewZoomLevel
		 * @param viewType
		 */
		public CustomBrMap(MapPanel panelLink, int iMapProvider, double viewCenterLatitude, double viewCenterLongitude, int viewZoomLevel,
				int viewType) {
			super(iMapProvider, viewCenterLatitude, viewCenterLongitude, viewZoomLevel, viewType);
			this.linkedPanel = panelLink;
		}

		@Override
		public void onFoundAddress(String[] args) {
			super.onFoundAddress(args);
			linkedPanel.forwardCoordinates(args[LAT], args[LON]);
		}

		@Override
		public void onMouseEvent(String type, String[] args) {
			super.onMouseEvent(type, args);
			linkedPanel.forwardMouseEvent(type, args);
		}

	}

	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				JFrame test = new JFrame("Map Bean Test");
				test.setSize(new Dimension(1024, 600));
				test.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
				test.add(new MapBean(null, 39.95938, -75.19481));
				test.setVisible(true);
				test.setLocationRelativeTo(null);
			}
		});
	}
	
}
